function isHashEmpty(h) {
	for (var s in h) {
		return false;
	}
	return true;
}
function hashToString(h) {
	var ret = "{";
	for (var s in h) {
		ret += s + "=" + h[s] + ",";
	}
	if (ret.length > 1) ret = ret.substring(0, ret.length - 1);
	ret += "}";
	return ret;
}
function hashToParam(h) {
	var ret = "";
	for (var s in h) {
		if (typeof h[s] == "string") {
			ret += "&" + s + "=" + h[s];
		} if (typeof h[s] == "number") {
			ret += "&" + s + "=" + h[s];
		} else if (typeof h[s] == "object" && h[s].length) {
			for (var i = 0; i < h[s].length; i++) {
				ret += "&" + s + "=" + h[s][i];
			}		
		} else {
			ret += "&" + s + "=" + h[s];
		}
	}
	return ret;
}
function hashToBool(h) {
	if (isHashEmpty(h)) return false;
	for (var s in h) {
		if (!h[s]) return false;
	}
	return true;
}
function keyOfHash(h) {
	var ret = new Array();
	for (var s in h) {
		ret[ret.length] = s;
	}
	return ret;
}

function copyCreateHash(h) {
	if (h) {
		var n = {};
		for (var k in h) {
			n[k] = h[k];
		}
		return n;
	} else {
		return {};
	}
}
function isHashEqual(h1, h2) {
	if (isHashEmpty(h1) && isHashEmpty(h2)) {
		return true;	
	} else if (isHashEmpty(h1) || isHashEmpty(h2)) {
		return false;
	} else {
		for (var k in h1) {
			if (h1[k] != h2[k]) return false;
		}
		return true;
	}
}
function copyCreateArray(a) {
	return a && a.length > 0 ? a.copy() : [];
}

//以下是一些基本的判断对象有效的函数
function isValid(v) {
	switch (typeof v) {
	  case "undefined":
		return false;
	  case "object":
		return v != null;
	  case "string":
		return v != "";
	  case "number":
		return !isNaN(v);
	  case "function":
	  case "boolean":
		return true;
	}
	return false;
}
function isInvalid(v) {
	switch (typeof v) {
	  case "undefined":
		return true;
	  case "object":
		return v == null;
	  case "string":
		return v == "";
	  case "number":
		return isNaN(v);
	  case "function":
	  case "boolean":
		return false;
	}
	return true;
}
function isValidNumber(v) {
	return typeof v == "number" && !isNaN(v);
}
function isInvalidNumber(v) {
	return typeof v != "number" || isNaN(v);
}
function isValidString(v) {
	return typeof v == "string" && v != "";
}
function isInvalidString(v) {
	return typeof v != "string" || v == "";
}
function isValidArray(v) {
	return typeof v == "object" && v != null && typeof v.push == "function";
}
function isInvalidArray(v) {
	return typeof v != "object" || v == null || typeof v.push != "function";
}
function isValidObject(v) {
	return typeof v == "object" && v != null && typeof v.push != "function";
}
function isInvalidObject(v) {
	return typeof v != "object" || v == null || typeof v.push == "function";
}
function isValidFunction(v) {
	return typeof v == "function";
}
function isInvalidFunction(v) {
	return typeof v == "function";
}
function getUnicodeLength(str) {
	if (str == null) {
		return 0;
	}
	var cArr = str.match(/[^x00-xff]/ig);
	return str.length + (cArr == null ? 0 : cArr.length);
}
function isPositiveInt(inputVal) {
	inputStr = inputVal.toString();
	for (var i = 0; i < inputStr.length; i++) {
		var oneChar = inputStr.charAt(i);
		if (oneChar < "0" || oneChar > "9") {
			return false;
		}
	}
	return true;
}
function isNumber(aValue) {
	return isValid(aValue) && !isNaN(aValue);
}
function isURL(aValue) {
	return true;
}
function isEmail(str){
	var pattern=/[a-zA-Z0-9_.]{1,}@[a-zA-Z0-9_]{1,}.[a-zA-Z0-9_]{1,}/;
	return checkRegexp(str,pattern);
}
function isWordChar(str){
	var pattern=/^[a-zA-Z0-9_]*$/;
	return checkRegexp(str,pattern);
}
function isPassword(str){
	var pattern=/^(\w){6,20}$/;
	return checkRegexp(str,pattern);
}
function isPhone(str){
	var pattern=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;
	return checkRegexp(str,pattern);
}
function isPostalCode(str){
	var pattern=/^[a-zA-Z0-9 ]{3,12}$/;
  	return checkRegexp(str,pattern);
}
function isDate(value) {
	if (!checkRegexp(value, /^\d{4}-\d{2}-\d{2}$/)) return false;
	var ds = value.split("-");
	var date = new Date(ds[0], ds[1]-1, ds[2]);
	return (date.getFullYear() == ds[0] && date.getMonth()+1 == ds[1] && date.getDate() == ds[2]);
}
function checkRegexp(strValue,strPattern){
	if(strValue.match(strPattern)==null){
		return false;
	}else{
		return true;
	}
}
function isFilterNumber(value) {
	return isFilter(value, "isNumber");
}
function isFilterPositiveInt(value) {
	return isFilter(value, "isPositiveInt");
}
function isFilterDate(value) {
	return isFilter(value, "isDate");
}
function isFilter(value, type) {
	var vs = value.split(",");
	for (i = 0; i < vs.length; i ++) {
		if (vs[i].toUpperCase() == "NULL") {
			continue;
		} else if ((j = vs[i].indexOf("..")) != -1) {
			min = vs[i].substring(0, j);
			max = vs[i].substring(j + 2);
			if (type == "isNumber") {
				if (!isNumber(min) || !isNumber(max))
					return false;
			} else if (type == "isPositiveInt") {
				if (!isPositiveInt(min) || !isPositiveInt(max))
					return false;
			} else if (type == "isDate") {
				if (!isDate(min) || !isDate(max))
					return false;
			}
		} else {
			if (type == "isNumber") {
				if (!isNumber(vs[i]))
					return false;
			} else if (type == "isPositiveInt") {
				if (!isPositiveInt(vs[i]))
					return false;
			} else if (type == "isDate") {
				if (!isDate(vs[i]))
					return false;
			} 
		}
	}
	return true;
}

//类型typeof的方法，专用于检查function，主要针对ie在typeof opener中对象的方法时的bug
function typeofFunction(targetObj, functionName) {
	if (document.all) {
		var funcObj = eval("targetObj." + functionName);
		if (funcObj) {
			var funStr = funcObj.toString();
			return (funStr && funStr.length >= 8 && funStr.substring(0, 8) == "function");
		} else {
			return false;
		}
	} else {
		return eval("typeof targetObj."+functionName) == "function";
	}
}



//以下是扩展Number对象
Number.prototype.limit = function (vmin, vmax) {
	if (vmax != null && typeof vmax == "number" && this > vmax) {
		return vmax;
	} else {
		if (vmin != null && typeof vmin == "number" && this < vmin) {
			return vmin;
		} else {
			return Number(this);
		}
	}
};
Number.prototype.inrange = function (vmin, vmax) {
	return this > vmin && this < vmax;
};

//以下是扩展Array对象
Array.prototype.indexOf = function (o) {
	for (var i = 0; i < this.length; i++) {
		if (this[i] == o) {
			return i;
		}
	}
	return -1;
};
Array.prototype.lastIndexOf = function (o) {
	for (var i = this.length - 1; i >= 0; i--) {
		if (this[i] == o) {
			return i;
		}
	}
	return -1;
};
Array.prototype.contains = function (o) {
	return this.indexOf(o) != -1;
};
Array.prototype.remove = function (o) {
	var i = this.indexOf(o);
	if (i != -1) {
		this.splice(i, 1);
	}
};
Array.prototype.insertAt = function (o, i) {
	this.splice(i, 0, o);
};
Array.prototype.insertBefore = function (o, o2) {
	var i = this.indexOf(o2);
	if (i == -1) {
		this.push(o);
	} else {
		this.splice(i, 0, o);
	}
};
Array.prototype.insertAfter = function (o, o2) {
	var i = this.indexOf(o2);
	if (i == -1 || i == (this.length - 1)) {
		this.push(o);
	} else {
		this.splice(i + 1, 0, o);
	}
};
Array.prototype.removeAt = function (i) {
	this.splice(i, 1);
};
Array.prototype.remove = function (o) {
	var i = this.indexOf(o);
	if (i != -1) {
		this.splice(i, 1);
	}
};
Array.prototype.copy = function () {
	return this.concat();
};
Array.prototype.getLast = function () {
	return this[this.length - 1];
};
Array.prototype.getFirst = function () {
	return this[0];
};
Array.prototype.swap = function (i, i1) {
	var t = this[i];
	this[i] = this[i1];
	this[i1] = t;
};


//以下是扩展String对象
String.prototype.contains = function (s) {
	return this.indexOf(s) != -1;
};
String.prototype.toFirstUp = function () {
	return this.charAt(0).toUpperCase() + this.substr(1);
};
String.prototype.toCamelCase = function () {
	var vArr = this.split("-");
	if (vArr.length == 1) {
		return vArr[0];
	}
	var ret = vArr[0];
	var s;
	for (var i = 1, len = vArr.length; i < len; i++, s = vArr[i]) {
		ret += s.charAt(0).toUpperCase() + s.substring(1);
	}
	return ret;
};
String.prototype.trimLeft = new Function("return this.replace(/^\\s+/,'')");
String.prototype.trimRight = new Function("return this.replace(/\\s+$/,'')");
String.prototype.trim = new Function("return this.replace(/^\\s+|\\s+$/g,'')");
String.prototype.add = function (v, sep) {
	if (this == v) {
		return this;
	} else {
		if (this == "") {
			return v;
		} else {
			if (isInvalid(sep)) {
				sep = ",";
			}
			var a = this.split(sep);
			if (a.indexOf(v) == -1) {
				a.push(v);
				return a.join(sep);
			} else {
				return this;
			}
		}
	}
};
String.prototype.remove = function (v, sep) {
	if (this == v || this == "") {
		return "";
	} else {
		if (isInvalid(sep)) {
			sep = ",";
		}
		var a = this.split(sep);
		var p = a.indexOf(v);
		if (p == -1) {
			return this;
		}
		do {
			a.splice(p, 1);
		} while ((p = a.indexOf(v)) != -1);
		return a.join(sep);
	}
};
String.prototype.startWith = function (s, ignorCase) {
	var s1 = this.substring(0, s.length);
	return (ignorCase) ? s1.toLowerCase() == s.toLowerCase() : s1 == s;
};
String.prototype.splitFirst = function (s) {
	var index = this.indexOf(s);
	var ret = new Array();
	if (index == -1) {
		ret[0] = this;
	} else {
		ret[0] = this.substring(0, index);
		ret[1] = this.substring(index+1);	
	}
	return ret
}

//以下是扩展Function对象
if (!Function.prototype.apply) {
	Function.prototype.apply = function (oScope, args) {
		var sarg = [];
		var rtrn, call;
		if (!oScope) {
			oScope = window;
		}
		if (!args) {
			args = [];
		}
		for (var i = 0; i < args.length; i++) {
			sarg[i] = "args[" + i + "]";
		}
		call = "oScope._applyTemp_(" + sarg.join(",") + ");";
		oScope._applyTemp_ = this;
		rtrn = eval(call);
		delete oScope._applyTemp_;
		return rtrn;
	};
}
Function.prototype.extend = function (sFunction, tClassName) {
	if (typeof sFunction != "function") {
		throw new Error("Extend:Function/Constructor to extend from is not a function:" + f);
	}
	if (typeof tClassName != "string") {
		throw new Error("Extend:Missing or malformed className:" + tClassName);
	}
	proto = this.prototype = new sFunction;
	proto.superclass = sFunction;
	proto.classname = tClassName;
	proto.constructor = this;
	return proto;
};

Function.prototype.removeProperty = function (p) {
	if (typeof this.prototype._i1 != "string") {
		throw new Error("Has no properties!");
	}
	if (typeof p != "object") {
		throw new Error("Param should be an object!");
	}
	if (isInvalid(p.name)) {
		throw new Error("Malformed input parameters:name needed!");
	}
	p.method = p.name.toFirstUp();
	p.implMethod = p.impl ? p.impl.toFirstUp() : p.method;
	var valueKey = "_value" + p.method;
	this.prototype._i1 = this.prototype._i1.remove(p.name);
	this.prototype[valueKey] = null;
	this.prototype["get" + p.method] = function () {
		return null;
	};
	this.prototype["force" + p.method] = this.prototype["set" + p.method] = function () {
		throw new Error("Property " + p.name + " is not supported by class+" + this.classname);
	};
	if (this.prototype["_e1" + p.method]) {
		this.prototype["_e1" + p.method] = null;
	}
	if (this.prototype["_e2" + p.method]) {
		this.prototype["_e2" + p.method] = null;
	}
};


//扩展Error对象
Error.prototype.toString = function () {
	return this.message;
};


//StringBuffer 类
function StringBuffer(bufferSize) {
	if (bufferSize) {
		this.bufferSize = bufferSize;
	} else {
		this.bufferSize = 500;
	}
	this.bf = new Array(this.bufferSize);
	this.top = 0;
	this.value = "";
	
	
	this.append = function append(str) {
		this.bf[this.top++] = str;
		if (this.top == this.bufferSize) {
			this.concatBuffer(this.top);
			this.top = 0;
		}
		return this;
	};
	
	this.toString = function toString() {
		this.concatBuffer(this.top);
		return this.value;
	};
	
	
	this.concatBuffer = function concatBuffer(endIndex) {
		for (var i = this.bufferSize - 1; i >= endIndex; i--) {
			this.bf[i] = "";
		}
		this.value = this.value.concat(this.bf.join(""));
	};
}

/*----------------------------------------------------------------------------\
|                                Range Class                                  |
|-----------------------------------------------------------------------------|
|                         Created by Erik Arvidsson                           |
|                  (http://webfx.eae.net/contact.html#erik)                   |
|                      For WebFX (http://webfx.eae.net/)                      |
|-----------------------------------------------------------------------------|
| Used to  model the data  used  when working  with  sliders,  scrollbars and |
| progress bars.  Based  on  the  ideas of  the javax.swing.BoundedRangeModel |
| interface  defined  by  Sun  for  Java;   http://java.sun.com/products/jfc/ |
| swingdoc-api-1.0.3/com/sun/java/swing/BoundedRangeModel.html                |
|-----------------------------------------------------------------------------|
|                Copyright (c) 2002, 2005, 2006 Erik Arvidsson                |
|-----------------------------------------------------------------------------|
| Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| use this file except in compliance with the License.  You may obtain a copy |
| of the License at http://www.apache.org/licenses/LICENSE-2.0                |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| Unless  required  by  applicable law or  agreed  to  in  writing,  software |
| distributed under the License is distributed on an  "AS IS" BASIS,  WITHOUT |
| WARRANTIES OR  CONDITIONS OF ANY KIND,  either express or implied.  See the |
| License  for the  specific language  governing permissions  and limitations |
| under the License.                                                          |
|-----------------------------------------------------------------------------|
| 2002-10-14 | Original version released                                      |
| 2005-10-27 | Use Math.round instead of Math.floor                           |
| 2006-05-28 | Changed license to Apache Software License 2.0.                |
|-----------------------------------------------------------------------------|
| Created 2002-10-14 | All changes are in the log above. | Updated 2006-05-28 |
\----------------------------------------------------------------------------*/


function Range() {
	this._value = 0;
	this._minimum = 0;
	this._maximum = 100;
	this._extent = 0;

	this._isChanging = false;
}

Range.prototype.setValue = function (value) {
	value = Math.round(parseFloat(value));
	if (isNaN(value)) return;
	if (this._value != value) {
		if (value + this._extent > this._maximum)
			this._value = this._maximum - this._extent;
		else if (value < this._minimum)
			this._value = this._minimum;
		else
			this._value = value;
		if (!this._isChanging && typeof this.onchange == "function")
			 this.onchange();
	}
};

Range.prototype.getValue = function () {
	return this._value;
};

Range.prototype.setExtent = function (extent) {
	if (this._extent != extent) {
		if (extent < 0)
			this._extent = 0;
		else if (this._value + extent > this._maximum)
			this._extent = this._maximum - this._value;
		else
			this._extent = extent;
		if (!this._isChanging && typeof this.onchange == "function")
			this.onchange();
	}
};

Range.prototype.getExtent = function () {
	return this._extent;
};

Range.prototype.setMinimum = function (minimum) {
	if (this._minimum != minimum) {
		var oldIsChanging = this._isChanging;
		this._isChanging = true;

		this._minimum = minimum;

		if (minimum > this._value)
			this.setValue(minimum);
		if (minimum > this._maximum) {
			this._extent = 0;
			this.setMaximum(minimum);
			this.setValue(minimum)
		}
		if (minimum + this._extent > this._maximum)
			this._extent = this._maximum - this._minimum;

		this._isChanging = oldIsChanging;
		if (!this._isChanging && typeof this.onchange == "function")
			this.onchange();
	}
};

Range.prototype.getMinimum = function () {
	return this._minimum;
};

Range.prototype.setMaximum = function (maximum) {
	if (this._maximum != maximum) {
		var oldIsChanging = this._isChanging;
		this._isChanging = true;

		this._maximum = maximum;

		if (maximum < this._value)
			this.setValue(maximum - this._extent);
		if (maximum < this._minimum) {
			this._extent = 0;
			this.setMinimum(maximum);
			this.setValue(this._maximum);
		}
		if (maximum < this._minimum + this._extent)
			this._extent = this._maximum - this._minimum;
		if (maximum < this._value + this._extent)
			this._extent = this._maximum - this._value;

		this._isChanging = oldIsChanging;
		if (!this._isChanging && typeof this.onchange == "function")
			this.onchange();
	}
};

Range.prototype.getMaximum = function () {
	return this._maximum;
};
















/*----------------------------------------------------------------------------\
|                                   IE Emu                                    |
|-----------------------------------------------------------------------------|
|                         Created by Erik Arvidsson                           |
|                  (http://webfx.eae.net/contact.html#erik)                   |
|                      For WebFX (http://webfx.eae.net/)                      |
|-----------------------------------------------------------------------------|
| A emulation of Internet Explorer DHTML Object Model for Mozilla             |
|-----------------------------------------------------------------------------|
|                  Copyright (c) 1999 - 2004 Erik Arvidsson                   |
|-----------------------------------------------------------------------------|
| This software is provided "as is", without warranty of any kind, express or |
| implied, including  but not limited  to the warranties of  merchantability, |
| fitness for a particular purpose and noninfringement. In no event shall the |
| authors or  copyright  holders be  liable for any claim,  damages or  other |
| liability, whether  in an  action of  contract, tort  or otherwise, arising |
| from,  out of  or in  connection with  the software or  the  use  or  other |
| dealings in the software.                                                   |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| This  software is  available under the  three different licenses  mentioned |
| below.  To use this software you must chose, and qualify, for one of those. |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| The WebFX Non-Commercial License          http://webfx.eae.net/license.html |
| Permits  anyone the right to use the  software in a  non-commercial context |
| free of charge.                                                             |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| The WebFX Commercial license           http://webfx.eae.net/commercial.html |
| Permits the  license holder the right to use  the software in a  commercial |
| context. Such license must be specifically obtained, however it's valid for |
| any number of  implementations of the licensed software.                    |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| GPL - The GNU General Public License    http://www.gnu.org/licenses/gpl.txt |
| Permits anyone the right to use and modify the software without limitations |
| as long as proper  credits are given  and the original  and modified source |
| code are included. Requires  that the final product, software derivate from |
| the original  source or any  software  utilizing a GPL  component, such  as |
| this, is also licensed under the GPL license.                               |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| MPL - Mozilla Public License                    http://www.mozilla.org/MPL/ |
|                                                                             |
| The contents of this file are subject to the Mozilla Public License Version |
| 1.1 (the "License"); you may not use this file except in compliance with    |
| the License. You may obtain a copy of the License at                        |
| http://www.mozilla.org/MPL/                                                 |
|                                                                             |
| Software distributed under the License is distributed on an "AS IS" basis,  |
| WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License    |
| for the specific language governing rights and limitations under the        |
| License.                                                                    |
|                                                                             |
| The Original Code is IE Emu.                                                |
|                                                                             |
| The Initial Developer of the Original Code is Erik Arvidsson.               |
| Portions created by the Initial Developer are Copyright (C) 1999-2004       |
| the Initial Developer. All Rights Reserved.                                 |
|                                                                             |
| Contributor(s):                                                             |
|                                                                             |
|-----------------------------------------------------------------------------|
| 2002-??-?? | First version                                                  |
| 2004-04-13 | Impreved currentStyle emulation. Updated to not that the code  |
|            |is available under GPL, MPL or WebFX Non-Commercial License     |
|-----------------------------------------------------------------------------|
| Created 2002-??-?? | All changes are in the log above. | Updated 2004-04-13 |
\----------------------------------------------------------------------------*/


//var ie = /MSIE/.test(navigator.userAgent);
//var moz = !ie && navigator.product == "Gecko";

/*
if (moz) {	// set up ie environment for Moz

	extendEventObject();
	//emulateAttachEvent();
	//emulateFromToElement();
	emulateEventHandlers(["click", "dblclick", "mouseover", "mouseout",
							"mousedown", "mouseup", "mousemove",
							"keydown", "keypress", "keyup"]);
	emulateDocumentAll();
	emulateElement()
	emulateCurrentStyle();

	// It is better to use a constant for event.button
	Event.LEFT = 0;
	Event.MIDDLE = 1;
	Event.RIGHT = 2;
}
else {
	Event = {};
	// IE is returning wrong button number
	Event.LEFT = 1;
	Event.MIDDLE = 4;
	Event.RIGHT = 2;
}
*/

/* Set up IE Emualtion for Mozilla */
//if (window.moz == true && (typeof window.emulateAttachEvent != "function" || typeof window.extendEventObject != "function"))
//	alert("Error! IE Emulation file not included.");
//
//if (window.moz) {
//	emulateAttachEvent();
//	extendEventObject();
//}
/* end Mozilla specific emulation initiation */

/*
 * Extends the event object with srcElement, cancelBubble, returnValue,
 * fromElement and toElement
 */
function extendEventObject() {
	Event.prototype.__defineSetter__("returnValue", function (b) {
		if (!b) this.preventDefault();
		return b;
	});

	Event.prototype.__defineSetter__("cancelBubble", function (b) {
		if (b) this.stopPropagation();
		return b;
	});

	Event.prototype.__defineGetter__("srcElement", function () {
		var node = this.target;
		while (node.nodeType != 1) node = node.parentNode;
		return node;
	});

	Event.prototype.__defineGetter__("fromElement", function () {
		var node;
		if (this.type == "mouseover")
			node = this.relatedTarget;
		else if (this.type == "mouseout")
			node = this.target;
		if (!node) return;
		while (node.nodeType != 1) node = node.parentNode;
		return node;
	});

	Event.prototype.__defineGetter__("toElement", function () {
		var node;
		if (this.type == "mouseout")
			node = this.relatedTarget;
		else if (this.type == "mouseover")
			node = this.target;
		if (!node) return;
		while (node.nodeType != 1) node = node.parentNode;
		return node;
	});

	Event.prototype.__defineGetter__("offsetX", function () {
		return this.layerX;
	});
	Event.prototype.__defineGetter__("offsetY", function () {
		return this.layerY;
	});
}

/*
 * Emulates element.attachEvent as well as detachEvent
 */
function emulateAttachEvent() {
	HTMLDocument.prototype.attachEvent =
	HTMLElement.prototype.attachEvent = function (sType, fHandler) {
		var shortTypeName = sType.replace(/on/, "");
		fHandler._ieEmuEventHandler = function (e) {
			window.event = e;
			return fHandler();
		};
		this.addEventListener(shortTypeName, fHandler._ieEmuEventHandler, false);
	};

	HTMLDocument.prototype.detachEvent =
	HTMLElement.prototype.detachEvent = function (sType, fHandler) {
		var shortTypeName = sType.replace(/on/, "");
		if (typeof fHandler._ieEmuEventHandler == "function")
			this.removeEventListener(shortTypeName, fHandler._ieEmuEventHandler, false);
		else
			this.removeEventListener(shortTypeName, fHandler, true);
	};
}

/*
 * This function binds the event object passed along in an
 * event to window.event
 */
function emulateEventHandlers(eventNames) {
	for (var i = 0; i < eventNames.length; i++) {
		document.addEventListener(eventNames[i], function (e) {
			window.event = e;
		}, true);	// using capture
	}
}

/*
 * Simple emulation of document.all
 * this one is far from complete. Be cautious
 */

function emulateAllModel() {
	var allGetter = function () {
		var a = this.getElementsByTagName("*");
		var node = this;
		a.tags = function (sTagName) {
			return node.getElementsByTagName(sTagName);
		};
		return a;
	};
	HTMLDocument.prototype.__defineGetter__("all", allGetter);
	HTMLElement.prototype.__defineGetter__("all", allGetter);
}

function extendElementModel() {
	HTMLElement.prototype.__defineGetter__("parentElement", function () {
		if (this.parentNode == this.ownerDocument) return null;
		return this.parentNode;
	});

	HTMLElement.prototype.__defineGetter__("children", function () {
		var tmp = [];
		var j = 0;
		var n;
		for (var i = 0; i < this.childNodes.length; i++) {
			n = this.childNodes[i];
			if (n.nodeType == 1) {
				tmp[j++] = n;
				if (n.name) {	// named children
					if (!tmp[n.name])
						tmp[n.name] = [];
					tmp[n.name][tmp[n.name].length] = n;
				}
				if (n.id)		// child with id
					tmp[n.id] = n
			}
		}
		return tmp;
	});

	HTMLElement.prototype.contains = function (oEl) {
		if (oEl == this) return true;
		if (oEl == null) return false;
		return this.contains(oEl.parentNode);
	};
}

function emulateCurrentStyle() {
	HTMLElement.prototype.__defineGetter__("currentStyle", function () {
		return this.ownerDocument.defaultView.getComputedStyle(this, null);
		/*
		var cs = {};
		var el = this;
		for (var i = 0; i < properties.length; i++) {
			cs.__defineGetter__(properties[i], encapsulateObjects(el, properties[i]));
		}
		return cs;
		*/
	});
}

function emulateHTMLModel() {

	// This function is used to generate a html string for the text properties/methods
	// It replaces '\n' with "<BR"> as well as fixes consecutive white spaces
	// It also repalaces some special characters
	function convertTextToHTML(s) {
		s = s.replace(/\&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/g, "<BR>");
		while (/\s\s/.test(s))
			s = s.replace(/\s\s/, "&nbsp; ");
		return s.replace(/\s/g, " ");
	}

	HTMLElement.prototype.insertAdjacentHTML = function (sWhere, sHTML) {
		var df;	// : DocumentFragment
		var r = this.ownerDocument.createRange();

		switch (String(sWhere).toLowerCase()) {
			case "beforebegin":
				r.setStartBefore(this);
				df = r.createContextualFragment(sHTML);
				this.parentNode.insertBefore(df, this);
				break;

			case "afterbegin":
				r.selectNodeContents(this);
				r.collapse(true);
				df = r.createContextualFragment(sHTML);
				this.insertBefore(df, this.firstChild);
				break;

			case "beforeend":
				r.selectNodeContents(this);
				r.collapse(false);
				df = r.createContextualFragment(sHTML);
				this.appendChild(df);
				break;

			case "afterend":
				r.setStartAfter(this);
				df = r.createContextualFragment(sHTML);
				this.parentNode.insertBefore(df, this.nextSibling);
				break;
		}
	};

	HTMLElement.prototype.__defineSetter__("outerHTML", function (sHTML) {
	   var r = this.ownerDocument.createRange();
	   r.setStartBefore(this);
	   var df = r.createContextualFragment(sHTML);
	   this.parentNode.replaceChild(df, this);

	   return sHTML;
	});

	HTMLElement.prototype.__defineGetter__("canHaveChildren", function () {
		switch (this.tagName) {
			case "AREA":
			case "BASE":
			case "BASEFONT":
			case "COL":
			case "FRAME":
			case "HR":
			case "IMG":
			case "BR":
			case "INPUT":
			case "ISINDEX":
			case "LINK":
			case "META":
			case "PARAM":
				return false;
		}
		return true;
	});

	HTMLElement.prototype.__defineGetter__("outerHTML", function () {
		var attr, attrs = this.attributes;
		var str = "<" + this.tagName;
		for (var i = 0; i < attrs.length; i++) {
			attr = attrs[i];
			if (attr.specified)
				str += " " + attr.name + '="' + attr.value + '"';
		}
		if (!this.canHaveChildren)
			return str + ">";

		return str + ">" + this.innerHTML + "</" + this.tagName + ">";
	});


	HTMLElement.prototype.__defineSetter__("innerText", function (sText) {
		this.innerHTML = convertTextToHTML(sText);
		return sText;
	});

	var tmpGet;
	HTMLElement.prototype.__defineGetter__("innerText", tmpGet = function () {
		var r = this.ownerDocument.createRange();
		r.selectNodeContents(this);
		return r.toString();
	});

	HTMLElement.prototype.__defineSetter__("outerText", function (sText) {
		this.outerHTML = convertTextToHTML(sText);
		return sText;
	});
	HTMLElement.prototype.__defineGetter__("outerText", tmpGet);

	HTMLElement.prototype.insertAdjacentText = function (sWhere, sText) {
		this.insertAdjacentHTML(sWhere, convertTextToHTML(sText));
	};
}



